
#include <stdio.h>  
#include <netinet/in.h>
#include <unistd.h>
#include <sys/socket.h>
#include "opencv2/opencv.hpp"
#include "Ffmpeg_Decode.h"


#include <list>
#include <thread>
#include <utility>
#include <mutex>

using namespace cv;

#define DEBUG
//
long consumptiontime;
long playframecount = 0;


//thread decode and show
std::mutex mtx_list;
std::list<std::pair<char*, int>> list_pbuff;
	
//Ffmpeg_Decoder ffmpegobj;

//socekt
typedef struct socket_info
{
	int serSocket;
	int numClient;
	sockaddr_in remoteAddr[10];
	//int nAddrLen[10];
	socklen_t nAddrLen[10];

}Socket_Udp_Server_Info;

Socket_Udp_Server_Info * initUdpServer()
{
	int i = 0;
	Socket_Udp_Server_Info * mSocketInfo = (Socket_Udp_Server_Info *)malloc(sizeof(Socket_Udp_Server_Info));

	mSocketInfo->serSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (mSocketInfo->serSocket == -1)
	{
		printf("socket error !");
		return 0;
	}

	sockaddr_in serAddr;
	serAddr.sin_family = AF_INET;
	serAddr.sin_port = htons(8888);
	serAddr.sin_addr.s_addr = INADDR_ANY;
	if (bind(mSocketInfo->serSocket, (sockaddr *)&serAddr, sizeof(serAddr)) == -1)
	{
		printf("bind error !");
		close(mSocketInfo->serSocket);
		return 0;
	}
	else
	{
		printf("bind succeed  ! \n");
	}
	mSocketInfo->nAddrLen[0] = sizeof(sockaddr_in);

	return mSocketInfo;
}

// 结束时候调用
void unitUdpServer(Socket_Udp_Server_Info * mSocketInfo)
{
	close(mSocketInfo->serSocket);
}

//Ffmpeg_Decoder ffmpegobj;
//decode func
void decode_show(Ffmpeg_Decoder &ffmpegobj)
{
   if (ffmpegobj.nDataLen <= 0)
   {
   	
       //houlc
       printf("[Error]ffmpegobj.nDataLen <=0 \n");
   	//break;
       return ;
   }
   else
   {
   	ffmpegobj.haveread = 0;
   	while (ffmpegobj.nDataLen > 0)
   	{
           usleep(1);
   		printf("[houlc-debug] av_parser_parse2..start..\n");
   		int nLength = av_parser_parse2(ffmpegobj.avParserContext, ffmpegobj.c, &ffmpegobj.yuv_buff,
   			&ffmpegobj.nOutSize, ffmpegobj.filebuf + ffmpegobj.haveread, ffmpegobj.nDataLen, 0, 0, 0);//查找帧头
   		printf("[houlc-debug] av_parser_parse2..ok..ret=%d\n", ffmpegobj.nOutSize);
   		ffmpegobj.nDataLen -= nLength;//查找过后指针移位标志
   		ffmpegobj.haveread += nLength;
   		if (ffmpegobj.nOutSize <= 0)
   		{

   			break;
   		}
   		ffmpegobj.avpkt.size = ffmpegobj.nOutSize;//将帧数据放进包中
   		ffmpegobj.avpkt.data = ffmpegobj.yuv_buff;
   		playframecount++;

           usleep(1);
   		printf("[houlc-debug] avcodec_decode_video2..start..\n");
   		ffmpegobj.decodelen = avcodec_decode_video2(ffmpegobj.c, ffmpegobj.m_pYUVFrame, &ffmpegobj.piclen, &ffmpegobj.avpkt);//解码
   		printf("[houlc-debug] avcodec_decode_video2..ret:%d.\n", ffmpegobj.decodelen);

   		printf("[houlc-debug] AVERROR_BUG=%ld\n", AVERROR_BUG);
           if(ffmpegobj.piclen<0)
   		{
   			printf("\n[houlc]decode len < 0!!!!\n");
   			break;
   		}
   		if (ffmpegobj.piclen)
   		{
   			if (ffmpegobj.finishInitScxt == false)//初始化格式转换函数  
   			{
   				ffmpegobj.finishInitScxt = true;
   				ffmpegobj.scxt = sws_getContext(ffmpegobj.c->width, ffmpegobj.c->height, ffmpegobj.c->pix_fmt,
   					ffmpegobj.c->width, ffmpegobj.c->height, AV_PIX_FMT_BGR24, SWS_POINT, NULL, NULL, NULL);

   				int width = ffmpegobj.c->width;
   				int height = ffmpegobj.c->height;
   				ffmpegobj.yuv_buff = new uint8_t[width * height * 2];//初始化YUV图像数据区
   				ffmpegobj.rgb_buff = new uint8_t[width * height * 3];//初始化RGB图像帧数据区
   				ffmpegobj.data[0] = ffmpegobj.rgb_buff;
   				ffmpegobj.linesize[0] = width * 3;
   			}
   			if (ffmpegobj.scxt != NULL)
   			{
                   usleep(1);
   				//YUV转rgb  
   				sws_scale(ffmpegobj.scxt, ffmpegobj.m_pYUVFrame->data, ffmpegobj.m_pYUVFrame->linesize, 0,
   					ffmpegobj.c->height, ffmpegobj.data, ffmpegobj.linesize);

                   usleep(1);
   				ffmpegobj.Ffmpeg_Decoder_Show((char*)ffmpegobj.rgb_buff, ffmpegobj.c->width, ffmpegobj.c->height);//解码图像显示   	
   			}
   		}
   	}
   }
}                                                                                                                                                                                             
                                                                                                                                                                                              
//thread func
void decode_show_func(Ffmpeg_Decoder& ffmpegobj)
{
    while(true){
        usleep(1);
        if(list_pbuff.empty()) {
            usleep(5);
            continue;
        }
//Houlc
        
        mtx_list.lock();

        char* pbuff = list_pbuff.front().first;
        int ilen = list_pbuff.front().second;

		memcpy(ffmpegobj.filebuf, pbuff, ilen);
        ffmpegobj.nDataLen = ilen;

        free(pbuff);
        list_pbuff.pop_front();

        mtx_list.unlock();

        //must memcpy(ffmpegobj), and set it's len before
        decode_show(ffmpegobj);
        

#ifdef DEBUG
		printf("server ret = %d \n", ilen);
#endif
        
    }

}


int main()
{
    Socket_Udp_Server_Info * mSocketUdpServerInfo = initUdpServer();

	int info[3];
	int flag = 0;
	int ret = 0;
	printf("wait for video flag...\n");
	ret = recvfrom(mSocketUdpServerInfo->serSocket, (char *)info, sizeof(int) * 3, 0,
		(sockaddr *)&mSocketUdpServerInfo->remoteAddr[0], &mSocketUdpServerInfo->nAddrLen[0]);
	int width = info[0];
	int height = info[1];
	int channel = info[2];
	int bufferSize = width * height * channel;
	flag = 1;
	printf("flag re succeed w=%d h=%d c=%d \n", width, height, channel);
	if (ret == sizeof(int))
	{
		printf("flag re succeed \n");
	}
	char * revBuffer = (char *)malloc(sizeof(char) * bufferSize);
	Mat reviMat = Mat(height, width, CV_8UC3);

	Ffmpeg_Decoder ffmpegobj;
	ffmpegobj.Ffmpeg_Decoder_Init();

    std::thread decode_thread(decode_show_func, std::ref(ffmpegobj));

	while (1)
	{
        usleep(1);
		size_t ret = recvfrom(mSocketUdpServerInfo->serSocket, revBuffer, bufferSize, 0, 
                                      (sockaddr *)&mSocketUdpServerInfo->remoteAddr[0], &mSocketUdpServerInfo->nAddrLen[0]);
		printf("server ret = %d \n", ffmpegobj.nDataLen);
		//ffmpegobj.nDataLen = recv(mSocketTcpServerInfo->sClient[0], revBuffer, bufferSize, 0);
		//memcpy(ffmpegobj.filebuf, revBuffer, ffmpegobj.nDataLen);
	    char * pbuf = (char *)malloc(sizeof(char) * ret + 1);
        memset(pbuf, 0, ret + 1);
        memcpy(pbuf, revBuffer, ret);

        mtx_list.lock();
        list_pbuff.push_back(std::pair<char*, int>(pbuf, ret));
        mtx_list.unlock();
        //decode_show(ffmpegobj);

	}
	printf("消耗时间%dms\n", clock() - consumptiontime);//消耗时间计算
	printf("平均1s解码帧数%lf\n", playframecount / ((clock() - consumptiontime) / (double)1000));//消耗时间计算
	printf("解码帧数%d\n", playframecount);

    decode_thread.join();


	ffmpegobj.Ffmpeg_Decoder_Close();//关闭解码器

	free(revBuffer);

	return 0;
}
